// 基础类型
(() => {
  // 布尔类型
  // 基本语法
  // let 变量名：数据类型 = 值
  let flag: boolean = true;
  console.log(flag);

  //   数字类型
  let a1: number = 10; // 十进制
  let a2: number = 0b1010; // 二进制
  let a3: number = 0o12; // 八进制
  let a4: number = 0xa; // 十六进制
  console.log(a1);
  console.log(a2);
  console.log(a3);
  console.log(a4);

  //   字符串类型---string
  let name: string = "aaa";
  name = "云淡清欢";
  // name = 12 // error
  let age: number = 3;
  const info = `My name is ${name}, I am ${age} years old!`;
  console.log(info);

  // undefined 和 null
  let u: undefined = undefined;
  let n: null = null;
  console.log(u);
  console.log(n);
  //   undefined 和 null 都可以作为其它类型的子类型，把undefined 和 null 赋值给其它类型的变量，如:number变量
  let num2: number = null;
  console.log(num2);
  console.log("=========================");

  // 数组类型
  // 数组定义方式1
  // 语法: let 变量名: 数据类型[] = [值1, 值2, 值3]
  let arr1: number[] = [10, 20, 30, 40, 50];
  console.log(arr1);

  // 数组定义方式2: 泛型写法
  //   语法: let 变量名: Array<数据类型> = [值1, 值2, 值3]
  let arr2: Array<number> = [100, 200, 300];
  console.log(arr2);
  console.log("=========================");
  // 注意问题：数组定义后，里面的数据的类型必须和定义数组的时候的类型是一致的，否则有错误提示信息，也不会编译通过的

  // 元组类型：在定义数组的时候，类型和数据的荷属一开始就已经限定了
  let arr3: [string, number, boolean] = ["大哥哥", 100.12345, true];
  console.log(arr3);
  // 注意问题：元组类型在使用时，数据类型的位置和数据的个数 应该和定义元组时的数据类型及位置保持一致
  console.log(arr3[0].split(""));
  console.log(arr3[1].toFixed(2));
  console.log("=========================");

  // 枚举类型, 枚举里面的每个数据值都可以叫元素
  enum Color {
    red,
    green,
    blue,
  }
  enum People {
    zhangsan = 10, // 10
    lisi, // 11 --- 根据张一个索引值+1
    wangwu = 88888, // 88888 --- 自定义索引值
    中文老哥 = "我是中文类",
  }
  // 定义一个color的枚举类型的变量来接收枚举的值
  let color: Color = Color.red;
  console.log(color);
  console.log(Color.red, Color.green, Color.blue);

  // 定义一个people的枚举类型变量来接收枚举的值
  let people: People = People.zhangsan;
  console.log(people);
  console.log(People.zhangsan, People.lisi, People.wangwu);
  console.log(People.中文老哥);

  // 例，枚举中的元素可以是中文的数据值，但是不推荐
  console.log(People[11]);
  console.log("=========================");

  // any类型
  let str: any = 100;
  console.log(str);
  let arr: any[] = [100, "天生我材必有用，千金散尽还复来", true];
  console.log(arr);
  console.log(arr[1].split(""));

  // 这种情况下能编译，但会报错，any类型有优点也有缺点
  // console.log(arr[0].split(''));

  // void类型:在函数声明时，小括号后面使用:void，代表的是该函数没有任何的返回值
  function showMsg(): void {
    console.log("我欲因之梦吴越，一夜飞度镜湖月");
    // return
    // return undefined
    return null;
  }
  console.log(showMsg());

  let vd: void = undefined;
  console.log(vd);
  console.log("=========================");

  // object 类型
  // 定义一个函数，参数是object类型，返回值也是object类型
  function getObj(obj: object): object {
    console.log(obj);
    return {
      name: "yzfeng",
      age: 24,
    };
  }
  // console.log(getObj({name:'哥哥', age: 18}));
  // console.log(getObj('123')); // 错误的
  // console.log(getObj(new String('123')));
  console.log(getObj(String));
  console.log("=========================");

  // 联合类型（Union Types）表示取值可以为多种类型中的一种
  // 需求1: 定义一个一个函数得到一个数字或字符串值的字符串形式值
  function getString1(str: number | string): string {
    return str.toString();
  }
  console.log(getString1("123"));
  console.log("=========================");

  // 类型断言
  // 类型断言的语法方式1：<类型>变量名
  // 类型断言的语法方式2： 值 as 类型
  function getString2(str: number | string): number {
    // return str.toString().length;
    // 如果str本身就是string类型，那么没有必要调用toString()方法的

    if ((<string>str).length) {
      // str.length存在吗？如果存在就说明str是string类型的
      // return (<string>str).length;
      return (str as string).length;
    } else {
      // 此时说明str是number类型
      return str.toString().length;
    }
  }
  console.log(getString2(12345));
  console.log(getString2("0123456"));

  // 类型推断  TS会在没有明确的指定类型的时候推测出一个类型
  // let txt = 100 // 推断为 number类型
  // txt = '哥，你是个好人' 
  // console.log(txt);// error Type 'string' is not assignable to type 'number'

  let txt2; // 推断为 any类型
  txt2 = 100
  txt2 = '哥哥，你好棒'
  console.log(txt2); // 哥哥，你好棒
  
})();
